﻿using Pay.Core;
using Pay.Data;
using Pay.DTO;
using Pay.IService;
using Pay.Service.Cache;
using Pay.TO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Pay.Service {
    public class PlayingService : ServiceBase, IPlayingService, IDisposable {
        private IUnitOfWork _iUnitOfWork;
        public PlayingService(IUnitOfWork iUnitOfWork) : base(iUnitOfWork) {
            _iUnitOfWork = iUnitOfWork;
        }

        #region 后台赛事管理
        /// <summary>
        /// 获得赛事列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<playing_dto> GetPlayings(PlayingQuery query) {
            var filter = PredicateBuilder.True<Playing>();
            if (!string.IsNullOrEmpty(query.team_title)) {
                filter = filter.And(c => c.HomeTeam.Title == query.team_title || c.GuestTeam.Title == query.team_title);
            }
            if (!string.IsNullOrEmpty(query.type)) {
                int value = int.Parse(query.type);
                filter = filter.And(c => c.PlayType == (EPlayType)value);
            }
            if (!string.IsNullOrEmpty(query.begin_time)) {
                DateTime time = DateTime.Parse(query.begin_time);
                filter = filter.And(c => c.PlayTime >= time);
            }
            if (!string.IsNullOrEmpty(query.end_time)) {
                DateTime time = DateTime.Parse(query.end_time).AddDays(1);
                filter = filter.And(c => c.PlayTime <= time);
            }
            if (query.is_end.HasValue) {
                if (query.is_end.Value == true)
                    filter = filter.And(c => c.WinTeamId.HasValue);
                else filter = filter.And(c => !c.WinTeamId.HasValue);
            }
            PagedResult<playing_dto> result = new PagedResult<playing_dto>();
            if (query.is_end.HasValue && query.is_end.Value == true)
                result = context.Playing.FromCachePaged<Playing, playing_dto>(query.page, query.size, filter, orderBy => orderBy.OrderBy(s => s.WinTeamId != null).ThenByDescending(o => o.PlayTime));
            else
                result = context.Playing.FromCachePaged<Playing, playing_dto>(query.page, query.size, filter, orderBy => orderBy.OrderBy(s => s.WinTeamId != null).ThenBy(o => o.PlayTime));
            return result;
        }

        /// <summary>
        /// 获得赛事
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public playing_dto GetPlaying(long id) {
            return context.Playing.Find(id).ToDtoObject<playing_dto>();
        }

        /// <summary>
        /// 新增赛事
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>

        public int AddPlaying(playing_dto dto) {
            if (dto.home_team_id == dto.guest_team_id)
                throw new ServerErrorException("主队客队不能相同");
            if (dto.participation_end_time > dto.play_time)
                throw new ServerErrorException("参与截止时间不能大于比赛时间");
            Playing model = new Playing();
            dto.ToDtoObject(model);
            model.ActivityType = EActivityType.WorldCup;
            context.Playing.Add(model);
            int result = _iUnitOfWork.Commit("Playing");
            return result;
        }

        /// <summary>
        /// 更新赛事获胜队伍
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public int UpdatePlaying(playing_dto dto) {
            Playing model = context.Playing.FindById(dto.id);
            model.WinTeamId = dto.win_team_id;
            int result = _iUnitOfWork.Commit("Playing");
            return result;
        }
        #endregion

        #region 后台赛事参与统计（查看参与队伍）
        /// <summary>
        /// 后台赛事参与统计（查看参与队伍）
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<playing_statistics_model> GetPlayingStatistics(PageQuery query) {
            var q = from p in context.Playing
                    select new playing_statistics_model {
                        playing_id = p.Id,
                        home_team_id = p.HomeTeamId,
                        home_team_title = p.HomeTeam.Title,
                        guest_team_id = p.GuestTeamId,
                        guest_team_title = p.GuestTeam.Title,
                        win_team_id = p.WinTeamId,
                        win_team_title = p.WinTeamId == null ? "" : p.WinTeamId == 0 ? "平局" : p.WinTeam.Title,
                        playing_time = p.PlayTime
                    };

            var rows = q.OrderByDescending(c => c.playing_time).Skip((query.page - 1) * query.size).Take(query.size).ToList()
                        .Select(o => new playing_statistics_model() {
                            playing_id = o.playing_id,
                            home_team_id = o.home_team_id,
                            home_team_title = o.home_team_title,
                            guest_team_id = o.guest_team_id,
                            guest_team_title = o.guest_team_title,
                            win_team_id = o.win_team_id,
                            win_team_title = o.win_team_title,
                            playing_time = o.playing_time,
                            participate_home_num = context.UserGuessPlayingHis.Where(t => t.PlayingId == o.playing_id && t.GuessTeamId == o.home_team_id).Sum(t => (int?)t.GuessNum) ?? 0,
                            participate_guest_num = context.UserGuessPlayingHis.Where(t => t.PlayingId == o.playing_id && t.GuessTeamId == o.guest_team_id).Sum(t => (int?)t.GuessNum) ?? 0,
                            participate_dogfall_num = context.UserGuessPlayingHis.Where(t => t.PlayingId == o.playing_id && t.GuessTeamId == 0).Sum(t => (int?)t.GuessNum) ?? 0,
                            total_participate_reddrill = context.UserGuessPlayingHis.Where(t => t.PlayingId == o.playing_id).Sum(t => (decimal?)t.ConsumeRedDrill) ?? 0,
                            win_participate_num = context.UserGuessPlayingHis.Where(t => t.PlayingId == o.playing_id && o.win_team_id != null && t.GuessTeamId == o.win_team_id).Sum(t => (int?)t.GuessNum) ?? 0,
                            win_reddrill_per = ((context.UserGuessPlayingHis.Where(t => t.PlayingId == o.playing_id && o.win_team_id != null && t.GuessTeamId == o.win_team_id).Sum(t => (int?)t.GuessNum) ?? 0) == 0
                                                ? 0 : (context.UserGuessPlayingHis.Where(t => t.PlayingId == o.playing_id).Sum(t => (decimal?)t.ConsumeRedDrill) ?? 0) / context.UserGuessPlayingHis.Where(t => t.PlayingId == o.playing_id && o.win_team_id != null && t.GuessTeamId == o.win_team_id).Sum(t => t.GuessNum)).ToString("0.######")

                        }).ToList();
            var result = new PagedResult<playing_statistics_model>(rows, q.Count(), query.page, query.size);
            return result;
        }
        #endregion

        #region 后台赛事参与用户
        /// <summary>
        /// 后台赛事参与用户
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<user_guess_playing_his_dto> GetUserGuessPlayingHiss(UserGuessPlayingHisQuery query) {
            var filter = PredicateBuilder.True<UserGuessPlayingHis>();
            if (!string.IsNullOrEmpty(query.playing_id)) {
                long value = long.Parse(query.playing_id);
                filter = filter.And(c => c.PlayingId == value);
            }

            if (query.user_id > 0) filter = filter.And(c => c.UserId == query.user_id);

            if (!string.IsNullOrEmpty(query.mobile)) {
                filter = filter.And(c => c.Merchant.Mobile == query.mobile);
            }
            var q = context.UserGuessPlayingHis.Where(filter);
            var rows = q.OrderByDescending(c => c.CreateTime).Skip((query.page - 1) * query.size).Take(query.size).ToList().ToDtoList<user_guess_playing_his_dto>();
            var result = new PagedResult<user_guess_playing_his_dto>(rows, q.Count(), query.page, query.size);
            //var result = context.UserGuessPlayingHis.FromNoCachePaged<UserGuessPlayingHis, user_guess_playing_his_dto>(query.page, query.size, filter, orderBy => orderBy.OrderByDescending(o => o.CreateTime));
            return result;
        }
        #endregion
        public bool SaveUserGuess(user_guess_dto dto) {
            var red = context.RedRecord.FirstOrDefault(s => s.MerchantId == dto.user_id);
            var active = context.Activity.FirstOrDefault(s => s.Type == EActivityType.WorldCup);
            decimal guessRed = dto.num * 0.1m;
            DateTime dt = DateTime.Now;
            if (red.TotalRedDrill - red.ConsumeRedDrill < guessRed) throw new ServerErrorException("红钻不足");
            var play = context.Playing.FindById(dto.play_id);
            if (play.WinTeamId != null) throw new ServerErrorException("比赛已结束");
            if (dt >= play.ParticipationEndTime) throw new ServerErrorException("比赛已停止投注");
            UserGuessPlayingHis guess = new UserGuessPlayingHis();
            guess.ConsumeRedDrill = guessRed;
            guess.CreateTime = DateTime.Now;
            guess.GuessNum = dto.num;
            guess.GuessTeamId = dto.team_id;
            guess.PlayingId = dto.play_id;
            guess.UserId = dto.user_id;
            context.UserGuessPlayingHis.Add(guess);
            red.ConsumeRedDrill += guessRed;
            RedRecordDetail recordDetail = new RedRecordDetail() {
                RedRecordId = red.Id,
                MerchantId = dto.user_id,
                RedDrill = guessRed,
                Type = 3,
                IsReceive = true,
                CreateTime = DateTime.Now.ToUnix(),
                RedProductionTime = 0
            };
            context.RedRecordDetail.Add(recordDetail);
            active.ParticipationNum += dto.num;
            int result = _iUnitOfWork.Commit("RedRecord" + dto.user_id);
            return result > 0;
        }
        /// <summary>
        /// 处理用户比赛开奖 
        /// </summary>
        /// <param name="userId"></param>
        public void DealUserGuess(long userId) {
            //获得的红钻 = 输的一方总红钻数 / 赢的一方用户总参与的次数X当前用户参与赢的次数
            //var plays = context.Playing.Where(s => s.WinTeamId != null).ToList();
            var red = context.RedRecord.FirstOrDefault(s => s.MerchantId == userId);
            var list = context.UserGuessPlayingHis.Where(s => s.GetRedDrill == null && s.Merchant.Id == userId).ToList();
            foreach (var guess in list) {
                var item = context.Playing.FirstOrDefault(s => s.Id == guess.PlayingId && s.WinTeamId != null);
                if (item != null) {
                    var failTotalRed = item.UserGuessPlayingHiss.Where(s => s.PlayingId == item.Id && s.GuessTeamId != item.WinTeamId).Select(s => s.ConsumeRedDrill).DefaultIfEmpty(0).Sum();
                    var winTotalNum = item.UserGuessPlayingHiss.Where(s => s.PlayingId == item.Id && s.GuessTeamId == item.WinTeamId).Select(s => s.GuessNum).DefaultIfEmpty(0).Sum();
                    var userWinNum = guess.GuessTeamId == item.WinTeamId ? guess.GuessNum : 0;
                    if (userWinNum > 0 && winTotalNum >= 0 && failTotalRed > 0) {
                        guess.GetRedDrill = guess.ConsumeRedDrill + failTotalRed / winTotalNum * userWinNum;
                    } else {
                        if (userWinNum == 0) guess.GetRedDrill = 0;
                        else if (winTotalNum == 0) guess.GetRedDrill = 0;
                        else if (failTotalRed == 0) guess.GetRedDrill = guess.ConsumeRedDrill;
                    }

                    if (guess.GetRedDrill > 0) {
                        DateTime dt;
                        if (item.PlayTime.Hour > 10) { dt = item.PlayTime.Date.AddHours(34); } else { dt = item.PlayTime.Date.AddHours(10); }
                        RedRecordDetail recordDetail = new RedRecordDetail() {
                            RedRecordId = red.Id,
                            MerchantId = userId,
                            RedDrill = guess.GetRedDrill.Value,
                            Type = 4,
                            IsReceive = true,
                            CreateTime = dt.ToUnix(),
                            RedProductionTime = 0
                        };
                        context.RedRecordDetail.Add(recordDetail);
                        red.TotalRedDrill += guess.GetRedDrill.Value;

                    }
                    int result = _iUnitOfWork.Commit("RedRecord" + userId);
                }
            }

        }

        /// <summary>
        /// 比赛开奖
        /// </summary>
        /// <param name="playingId"></param>
        /// <returns></returns>
        public int DealPlayingLottery(long playingId) {
            int result = 0;
            Playing playing = context.Playing.Where(o => o.Id == playingId).FirstOrDefault();
            if (playing.WinTeamId == null)
                throw new ServerErrorException("未设置胜利队伍");

            List<UserGuessPlayingHis> userGuessPlayingHisList = context.UserGuessPlayingHis.Where(o => o.GetRedDrill == null && o.PlayingId == playingId).ToList();
            if (userGuessPlayingHisList != null && userGuessPlayingHisList.Count() > 0) {
                var failTotalRed = playing.UserGuessPlayingHiss.Where(s => s.PlayingId == playing.Id && s.GuessTeamId != playing.WinTeamId).Select(s => s.ConsumeRedDrill).DefaultIfEmpty(0).Sum();
                var winTotalNum = playing.UserGuessPlayingHiss.Where(s => s.PlayingId == playing.Id && s.GuessTeamId == playing.WinTeamId).Select(s => s.GuessNum).DefaultIfEmpty(0).Sum();
                var tags = new List<string>();
                foreach (var guess in userGuessPlayingHisList) {
                    var red = context.RedRecord.FirstOrDefault(s => s.MerchantId == guess.UserId);
                    tags.Add("RedRecord" + guess.UserId);
                    var userWinNum = guess.GuessTeamId == playing.WinTeamId ? guess.GuessNum : 0;
                    if (userWinNum > 0 && winTotalNum >= 0 && failTotalRed > 0) {
                        guess.GetRedDrill = guess.ConsumeRedDrill + failTotalRed / winTotalNum * userWinNum;
                    } else {
                        if (userWinNum == 0) guess.GetRedDrill = 0;
                        else if (winTotalNum == 0) guess.GetRedDrill = 0;
                        else if (failTotalRed == 0) guess.GetRedDrill = guess.ConsumeRedDrill;
                    }

                    if (guess.GetRedDrill > 0) {
                        RedRecordDetail recordDetail = new RedRecordDetail() {
                            RedRecordId = red.Id,
                            MerchantId = guess.UserId,
                            RedDrill = guess.GetRedDrill.Value,
                            Type = 4,
                            IsReceive = true,
                            CreateTime = DateTime.Now.ToUnix(),
                            RedProductionTime = 0
                        };
                        context.RedRecordDetail.Add(recordDetail);
                        red.TotalRedDrill += guess.GetRedDrill.Value;

                    }

                }
                result = _iUnitOfWork.Commit(tags.ToArray());
            }


            return result;

        }

    }
}
